package org.xx.armory.swing;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.math.BigDecimal;
import java.util.Date;
import java.util.function.Consumer;

/**
 * UI控制器，设置组件属性和布局的工具类。
 */
public interface UIController {
    /**
     * 控制器加载时触发，此时开始设置组件属性和执行布局。
     */
    void load();

    /**
     * 将Action关联到指定的事件响应程序。
     * <p>如果找不到指定名字的Action，则不执行任何操作。</p>
     * <p>如果参数{@code eventHandler}是{@code null}，那么该Action不关联到任何响应程序。</p>
     *
     * @param actionName
     *         Action的名字，自动去掉首尾空格。
     * @param eventHandler
     *         事件响应程序。
     * @throws IllegalArgumentException
     *         如果参数{@code actionName}是{@code null}或者只包含空白字符。
     */
    void connect(
            String actionName,
            Consumer<ActionEvent> eventHandler
    );

    /**
     * 执行指定名字的Action。
     *
     * @param actionName
     *         Action的名字，自动去掉首尾空格。
     * @throws IllegalArgumentException
     *         如果参数{@code actionName}是{@code null}或者只包含空白字符，或者指定名字的Action不存在。
     */
    void call(
            String actionName
    );

    /**
     * 将指定的组件的指定事件关联到指定的事件响应程序。
     * <p>如果参数{@code name}是{@code null}或者是空字符串，那么表示组件是控制器本身。</p>
     * <p>如果参数{@code eventHandler}是{@code null}，那么该组件的该事件不关联到任何响应程序。</p>
     *
     * @param name
     *         组件的名字，自动去掉首尾空格。
     * @param eventName
     *         组件的事件名字，自动去掉首尾空格。
     * @param eventHandler
     *         事件响应程序。
     * @throws IllegalArgumentException
     *         如果参数{@code eventName}是{@code null}或者只包含空白字符，如果找不到指定名字的组件，如果无法关联指定名字的事件。
     */
    void connect(
            String name,
            String eventName,
            Consumer<Object> eventHandler
    );

    /**
     * 禁用Action
     *
     * @param actionName
     *         Action的名字，自动去掉首尾空格。
     * @throws IllegalArgumentException
     *         如果参数{@code actionName}是{@code null}或者只包含空白字符，如果找不到指定名字的Action。
     */
    void disable(
            String actionName
    );

    /**
     * 启用Action
     *
     * @param actionName
     *         Action的名字，自动去掉首尾空格。
     * @throws IllegalArgumentException
     *         如果参数{@code actionName}是{@code null}或者只包含空白字符，如果找不到指定名字的Action。
     */
    void enable(
            String actionName
    );

    /**
     * 显示指定的组件。
     *
     * @param name
     *         组件名字，自动去掉首尾空格。
     * @throws IllegalArgumentException
     *         如果参数{@code name}是{@code null}或者只包含空白字符，如果找不到指定名字的组件。
     */
    void show(
            String name
    );

    /**
     * 隐藏指定的组件。
     *
     * @param name
     *         组件名字，自动去掉首尾空格。
     * @throws IllegalArgumentException
     *         如果参数{@code name}是{@code null}或者只包含空白字符，如果找不到指定名字的组件。
     */
    void hide(
            String name
    );

    /**
     * 改变指定的组件的只读状态。
     * <p>如果参数{@code name}是{@code null}或者是空字符串，那么修改控制器创建的所有组件的只读状态，跳过那些无法设置只读状态的组件。</p>
     *
     * @param name
     *         组件名字，自动去掉首尾空格。
     * @param value
     *         只读状态，{@code true}表示只读，{@code false}表示可用。
     * @throws IllegalArgumentException
     *         如果参数{@code name}是{@code null}或者只包含空白字符，如果找不到指定名字的组件，或者无法为指定的组件设置只读状态。
     */
    void readOnly(
            String name,
            boolean value
    );

    /**
     * 获取指定名字的组件。
     *
     * @param clazz
     *         组件的类型。
     * @param name
     *         组件的名字。
     * @param <C>
     *         组件的类型。
     * @return 指定名字的组件。
     * @throws IllegalArgumentException
     *         如果参数{@code name}是{@code null}或者只包含空白字符，或者指定名字的组件不存在。
     * @throws ClassCastException
     *         如果指定的组件存在，但是无法转化为指定的类型{@code C}
     */
    <C extends Component> C get(
            Class<C> clazz,
            String name
    );

    /**
     * 获取指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @return 组件的值。
     */
    String getText(
            String name
    );

    /**
     * 设置指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @param text
     *         组件的值。
     */
    void setText(
            String name,
            String text
    );

    /**
     * 获取指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @return 组件的值。
     */
    String[] getValues(
            String name
    );

    /**
     * 设置指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @param values
     *         组件的值。
     */
    void setValues(
            String name,
            String[] values
    );

    /**
     * 获取指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @return 组件的值，如果无法转为整数则返回{@code 0}。
     */
    int getInteger(
            String name
    );

    /**
     * 设置指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @param value
     *         组件的值。
     */
    void setInteger(
            String name,
            Integer value
    );

    /**
     * 获取指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @return 组件的值，如果无法解析为长整数则返回{@code null}。
     */
    Long getNumber(
            String name
    );

    /**
     * 设置指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @param number
     *         组件的值。
     */
    void setNumber(
            String name,
            Long number
    );

    /**
     * 获取指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @return 组件的值，如果无法解析为浮点数则返回{@code null}。
     */
    Double getFloat(
            String name
    );

    /**
     * 设置指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @param value
     *         组件的值。
     */
    void setFloat(
            String name,
            Double value
    );

    /**
     * 获取指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @return 组件的值，如果无法解析为十进制数则返回{@code null}。
     */
    BigDecimal getDecimal(
            String name
    );

    /**
     * 设置指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @param decimal
     *         组件的值。
     */
    void setDecimal(
            String name,
            BigDecimal decimal
    );

    /**
     * 获取指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @return 组件的值，如果无法解析为日期则返回{@code null}。
     */
    Date getDate(
            String name
    );

    /**
     * 设置指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @param date
     *         组件的值。
     */
    void setDate(
            String name,
            Date date
    );

    /**
     * 获取指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @return 组件的值，如果无法解析为布尔值则返回{@code null}。
     * @see UIUtils#toBooleanObject(String)
     */
    Boolean getBoolean(
            String name
    );

    /**
     * 设置指定组件的值。
     *
     * @param name
     *         组件的名字。
     * @param value
     *         组件的值。
     */
    void setBoolean(
            String name,
            Boolean value
    );

    /**
     * 找到指定名字的消息字面量。
     *
     * @param name
     *         名字。
     * @return 消息字面量的值，如果不存在则返回该消息字面量的名字。
     */
    String getMessage(
            String name
    );

    /**
     * 找到指定名字的字面量并格式化。
     *
     * @param name
     *         字面量的名字。
     * @param values
     *         格式化占位符对应的值。
     * @return 格式化的结果，如果找不到对应的字面量则返回该字面量的名字，如果字面量中不包含占位符则忽略参数{@code values}。
     */
    String formatMessage(
            String name,
            Object... values
    );
}
